# import os
# import json
# import argparse
# import sys
# import shutil
# from lxml import etree
# from tqdm import tqdm
#
# category_set = set()
# image_set = set()
# bbox_nums = 0
#
#
# def parse_xml_to_dict(xml):
#     """
#     将xml文件解析成字典形式，参考tensorflow的recursive_parse_xml_to_dict
#     Args:
#         xml: xml tree obtained by parsing XML file contents using lxml.etree
#
#     Returns:
#         Python dictionary holding XML contents.
#     """
#     if len(xml) == 0:  # 遍历到底层，直接返回tag对应的信息
#         return {xml.tag: xml.text}
#
#     result = {}
#     for child in xml:
#         child_result = parse_xml_to_dict(child)  # 递归遍历标签信息
#         if child.tag != 'object':
#             result[child.tag] = child_result[child.tag]
#         else:
#             if child.tag not in result:  # 因为object可能有多个，所以需要放入列表里
#                 result[child.tag] = []
#             result[child.tag].append(child_result[child.tag])
#     return {xml.tag: result}
#
#
# def write_classIndices(category_set):
#     class_indices = dict((k, v) for v, k in enumerate(category_set))
#     json_str = json.dumps(dict((val, key) for key, val in class_indices.items()), indent=4)
#     with open('class_indices.json', 'w') as json_file:
#         json_file.write(json_str)
#
#
# def xyxy2xywhn(bbox, size):
#     bbox = list(map(float, bbox))
#     size = list(map(float, size))
#     xc = (bbox[0] + (bbox[2] - bbox[0]) / 2.) / size[0]
#     yc = (bbox[1] + (bbox[3] - bbox[1]) / 2.) / size[1]
#     wn = (bbox[2] - bbox[0]) / size[0]
#     hn = (bbox[3] - bbox[1]) / size[1]
#     return (xc, yc, wn, hn)
#
#
# def parser_info(info: dict, only_cat=True, class_indices=None):
#     filename = info['annotation']['filename']
#     image_set.add(filename)
#     objects = []
#     width = int(info['annotation']['size']['width'])
#     height = int(info['annotation']['size']['height'])
#     for obj in info['annotation']['object']:
#         obj_name = obj['name']
#         category_set.add(obj_name)
#         if only_cat:
#             continue
#         xmin = int(obj['bndbox']['xmin'])
#         ymin = int(obj['bndbox']['ymin'])
#         xmax = int(obj['bndbox']['xmax'])
#         ymax = int(obj['bndbox']['ymax'])
#         bbox = xyxy2xywhn((xmin, ymin, xmax, ymax), (width, height))
#         if class_indices is not None:
#             obj_category = class_indices[obj_name]
#             object = [obj_category, bbox]
#             objects.append(object)
#
#     return filename, objects
#
#
# def parseXmlFilse(voc_dir, save_dir):
#     assert os.path.exists(voc_dir), "ERROR {} does not exists".format(voc_dir)
#     if os.path.exists(save_dir):
#         shutil.rmtree(save_dir)
#     os.makedirs(save_dir)
#
#     xml_files = [os.path.join(voc_dir, i) for i in os.listdir(voc_dir) if os.path.splitext(i)[-1] == '.xml']
#     for xml_file in xml_files:
#         with open(xml_file) as fid:
#             xml_str = fid.read()
#         xml = etree.fromstring(xml_str)
#         info_dict = parse_xml_to_dict(xml)
#         parser_info(info_dict, only_cat=True)
#
#     with open(save_dir + "/classes.txt", 'w') as classes_file:
#         for cat in sorted(category_set):
#             classes_file.write("{}\n".format(cat))
#
#     class_indices = dict((v, k) for k, v in enumerate(sorted(category_set)))
#
#     xml_files = tqdm(xml_files)
#     for xml_file in xml_files:
#         with open(xml_file) as fid:
#             xml_str = fid.read()
#         xml = etree.fromstring(xml_str)
#         info_dict = parse_xml_to_dict(xml)
#         filename, objects = parser_info(info_dict, only_cat=False, class_indices=class_indices)
#         if len(objects) != 0:
#             global bbox_nums
#             bbox_nums += len(objects)
#             with open(save_dir + "/" + filename.split(".")[0] + ".txt", 'w') as f:
#                 for obj in objects:
#                     f.write(
#                         "{} {:.5f} {:.5f} {:.5f} {:.5f}\n".format(obj[0], obj[1][0], obj[1][1], obj[1][2], obj[1][3]))
#
#
# if __name__ == '__main__':
#     parser = argparse.ArgumentParser()
#     parser.add_argument('--voc-dir', type=str, default='./data/labels/voc')
#     parser.add_argument('--save-dir', type=str, default='./data/convert/yolo')
#     opt = parser.parse_args()
#     if len(sys.argv) > 1:
#         print(opt)
#         parseXmlFilse(**vars(opt))
#         print("image nums: {}".format(len(image_set)))
#         print("category nums: {}".format(len(category_set)))
#         print("bbox nums: {}".format(bbox_nums))
#     else:
#         voc_dir = 'F:\图像处理数据集\VOC2012\Annotations'
#         save_dir = 'F:\图像处理数据集\VOC2012/yolo'
#         parseXmlFilse(voc_dir, save_dir)
#         print("image nums: {}".format(len(image_set)))
#         print("category nums: {}".format(len(category_set)))
#         print("bbox nums: {}".format(bbox_nums))
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import random
from shutil import copyfile

classes = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog',
        'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] # 划分的类别，依实际情况而定
# classes=["ball"]

TRAIN_RATIO = 80  # 训练集与数据集划分的比例


def clear_hidden_files(path):
    dir_list = os.listdir(path)
    for i in dir_list:
        abspath = os.path.join(os.path.abspath(path), i)
        if os.path.isfile(abspath):
            if i.startswith("._"):
                os.remove(abspath)
        else:
            clear_hidden_files(abspath)


def convert(size, box): # 边界框的转换
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)


def convert_annotation(image_id):
    in_file = open('VOCdevkit/VOC2012/Annotations/%s.xml' % image_id) # xml路径
    out_file = open('VOCdevkit/VOC2012/YOLOLabels/%s.txt' % image_id, 'w')
    tree = ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        difficult = obj.find('difficult').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult) == 1:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
             float(xmlbox.find('ymax').text))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
    in_file.close()
    out_file.close()


wd = os.getcwd()
wd = os.getcwd()
data_base_dir = os.path.join(wd, "VOCdevkit/")
if not os.path.isdir(data_base_dir):
    os.mkdir(data_base_dir)
work_sapce_dir = os.path.join(data_base_dir, "VOC2012/")
if not os.path.isdir(work_sapce_dir):
    os.mkdir(work_sapce_dir)
annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
if not os.path.isdir(annotation_dir):
    os.mkdir(annotation_dir)
clear_hidden_files(annotation_dir)
image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
if not os.path.isdir(image_dir):
    os.mkdir(image_dir)
clear_hidden_files(image_dir)
yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
if not os.path.isdir(yolo_labels_dir):
    os.mkdir(yolo_labels_dir)
clear_hidden_files(yolo_labels_dir)
yolov5_images_dir = os.path.join(data_base_dir, "images/")
if not os.path.isdir(yolov5_images_dir):
    os.mkdir(yolov5_images_dir)
clear_hidden_files(yolov5_images_dir)
yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
if not os.path.isdir(yolov5_labels_dir):
    os.mkdir(yolov5_labels_dir)
clear_hidden_files(yolov5_labels_dir)
yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
if not os.path.isdir(yolov5_images_train_dir):
    os.mkdir(yolov5_images_train_dir)
clear_hidden_files(yolov5_images_train_dir)
yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
if not os.path.isdir(yolov5_images_test_dir):
    os.mkdir(yolov5_images_test_dir)
clear_hidden_files(yolov5_images_test_dir)
yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
if not os.path.isdir(yolov5_labels_train_dir):
    os.mkdir(yolov5_labels_train_dir)
clear_hidden_files(yolov5_labels_train_dir)
yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
if not os.path.isdir(yolov5_labels_test_dir):
    os.mkdir(yolov5_labels_test_dir)
clear_hidden_files(yolov5_labels_test_dir)

train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
train_file.close()
test_file.close()
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
list_imgs = os.listdir(image_dir)  # list image files
prob = random.randint(1, 100)
print("Probability: %d" % prob)
for i in range(0, len(list_imgs)):
    path = os.path.join(image_dir, list_imgs[i])
    if os.path.isfile(path):
        image_path = image_dir + list_imgs[i]
        voc_path = list_imgs[i]
        (nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
        (voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
        annotation_name = nameWithoutExtention + '.xml'
        annotation_path = os.path.join(annotation_dir, annotation_name)
        label_name = nameWithoutExtention + '.txt'
        label_path = os.path.join(yolo_labels_dir, label_name)
    prob = random.randint(1, 100)
    print("Probability: %d" % prob)
    if (prob < TRAIN_RATIO):  # train dataset
        if os.path.exists(annotation_path):
            train_file.write(image_path + '\n')
            convert_annotation(nameWithoutExtention)  # convert label
            copyfile(image_path, yolov5_images_train_dir + voc_path)
            copyfile(label_path, yolov5_labels_train_dir + label_name)
    else:  # test dataset
        if os.path.exists(annotation_path):
            test_file.write(image_path + '\n')
            convert_annotation(nameWithoutExtention)  # convert label
            copyfile(image_path, yolov5_images_test_dir + voc_path)
            copyfile(label_path, yolov5_labels_test_dir + label_name)
train_file.close()
test_file.close()

